home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 March / macformat-022.iso / Shareware City / Science / µSim 1.0b5 folder / source / Input.c < prev    next >
Encoding:
Text File  |  1994-10-04  |  14.7 KB  |  499 lines  |  [TEXT/MMCC]

  1. /*
  2. Copyright © 1993,1994 by Fabrizio Oddone
  3. ••• ••• ••• ••• ••• ••• ••• ••• ••• •••
  4. This source code is distributed as freeware: you can copy, exchange, modify this
  5. code as you wish. You may include this code in any kind of application: freeware,
  6. shareware, or commercial, provided that full credits are given.
  7. You may not sell or distribute this code for profit.
  8. */
  9.  
  10. //#pragma load "MacDump"
  11.  
  12. #include    "CursorBalloon.h"
  13. #include    "Globals.h"
  14. #include    "Input.h"
  15. #include    "Main.h"
  16. #include    "SimUtils.h"
  17.  
  18. //#pragma segment Main
  19.  
  20. /*    kTextMargin is the number of pixels we leave blank at the edge of the window. */
  21. enum {
  22. kTextMargin = 2,
  23.  
  24. /*    kCrChar is used to match with a carriage return when calculating the
  25.     number of lines in the TextEdit record. */
  26. kCrChar = 13,
  27.  
  28. /*    kButtonScroll is how many pixels to scroll horizontally when the button part
  29.     of the horizontal scrollbar is pressed. */
  30. kButtonScroll = 4
  31. };
  32.     
  33. /* static routines */
  34. static void GetLocalUpdateRgn(WindowPtr window, RgnHandle localRgn);
  35. static pascal void VActionProc(ControlHandle control, short part);
  36. static pascal void HActionProc(ControlHandle control, short part);
  37. static void DrawWindow(WindowPtr window);
  38. static void AdjustTE(WindowPtr window);
  39. static void AdjustHorz(ControlHandle control, TEHandle docTE);
  40. static void AdjustVert(ControlHandle control, TEHandle docTE);
  41. static void AdjustScrollSizes(WindowPtr window);
  42. static void AdjustScrollValues(WindowPtr window);
  43. static short LinesInTE(TEHandle theTE);
  44.  
  45.  
  46. void IOHome(void)
  47. {
  48. register ControlHandle    vscrollBar = ((DocumentPeek)gWPtr_IO)->docVScroll;
  49.  
  50. SetCtlValue(vscrollBar, GetCtlMin(vscrollBar));
  51. AdjustTE(gWPtr_IO);
  52. }
  53.  
  54. void IOEnd(void)
  55. {
  56. register ControlHandle    vscrollBar = ((DocumentPeek)gWPtr_IO)->docVScroll;
  57.  
  58. SetCtlValue(vscrollBar, GetCtlMax(vscrollBar));
  59. AdjustTE(gWPtr_IO);
  60. }
  61.  
  62. void IOPgUp(void)
  63. {
  64. VActionProc(((DocumentPeek)gWPtr_IO)->docVScroll, inPageUp);
  65. }
  66.  
  67. void IOPgDn(void)
  68. {
  69. VActionProc(((DocumentPeek)gWPtr_IO)->docVScroll, inPageDown);
  70. }
  71.  
  72. /*    Called when a mouseDown occurs in the grow box of an active window. In
  73.     order to eliminate any 'flicker', we want to invalidate only what is
  74.     necessary. Since ResizeWindow invalidates the whole portRect, we save
  75.     the old TE viewRect, intersect it with the new TE viewRect, and
  76.     remove the result from the update region. However, we must make sure
  77.     that any old update region that might have been around gets put back. */
  78.  
  79. void DoGrowWindow(WindowPtr window, EventRecord    *event)
  80. {
  81. Rect    tempRect;
  82. register long    growResult;
  83. register RgnHandle    tempRgn;
  84. register DocumentPeek doc;
  85.  
  86. if (window == gWPtr_IO) {
  87.     tempRect.right = tempRect.bottom = 0x7FFF;        /* set up limiting values */
  88.     tempRect.top = tempRect.left = kMinDocDim;
  89. /* see if it really changed size */
  90.     if (growResult = GrowWindow(window, event->where, &tempRect)) {
  91.         doc = (DocumentPeek) window;
  92.         tempRect = (*doc->docTE)->viewRect;        /* save old text box */
  93.         tempRgn = NewRgn();
  94.         GetLocalUpdateRgn(window, tempRgn);        /* get localized update region */
  95.         SizeWindow((WindowPtr)doc, LoWrd(growResult), HiWrd(growResult), true);
  96.         ResizeWindow((WindowPtr)doc);
  97. /* calculate & validate the region that hasn’t changed so it won’t get redrawn */
  98.         SectRect(&tempRect, &(*doc->docTE)->viewRect, &tempRect);
  99.         ValidRect(&tempRect);                /* take it out of update */
  100.         InvalRgn(tempRgn);                    /* put back any prior update */
  101.         DisposeRgn(tempRgn);
  102.         }
  103.     }
  104. } /* DoGrowWindow */
  105.  
  106.  
  107. /*     Called when a mouseClick occurs in the zoom box of an active window.
  108.     Everything has to get re-drawn here, so we don't mind that
  109.     ResizeWindow invalidates the whole portRect. */
  110.  
  111. void DoZoomWindow(WindowPtr window)
  112. {
  113. AdjustScrollbars(window, true);
  114. AdjustTE(window);
  115. } /*  DoZoomWindow */
  116.  
  117.  
  118. /* Called when the window has been resized to fix up the controls and content. */
  119.  
  120. void ResizeWindow(WindowPtr window)
  121. {
  122. InvalRect(&window->portRect);
  123. AdjustScrollbars(window, true);
  124. AdjustTE(window);
  125. } /* ResizeWindow */
  126.  
  127.  
  128. /* Returns the update region in local coordinates */
  129.  
  130. void GetLocalUpdateRgn(WindowPtr window, RgnHandle localRgn)
  131. {
  132. CopyRgn(((WindowPeek) window)->updateRgn, localRgn);/* save old update region */
  133. OffsetRgn(localRgn, window->portBits.bounds.left, window->portBits.bounds.top);
  134. } /* GetLocalUpdateRgn */
  135.  
  136.  
  137. /*    This is called when an update event is received for a window.
  138.     It calls DrawWindow to draw the contents of an application window.
  139.     As an efficiency measure that does not have to be followed, it
  140.     calls the drawing routine only if the visRgn is non-empty. This
  141.     will handle situations where calculations for drawing or drawing
  142.     itself is very time-consuming. */
  143.  
  144. void DoUpdateWindow(WindowPtr window)
  145. {
  146. if (window == gWPtr_IO)
  147.     if (EmptyRgn(window->visRgn) == false)    /* draw if updating needs to be done */
  148.         DrawWindow(window);
  149. } /*DoUpdate*/
  150.  
  151.  
  152. /*    This is called when a window is activated or deactivated.
  153.     It calls TextEdit to deal with the selection. */
  154.  
  155. void DoActivateWindow(WindowPtr window, Boolean becomingActive)
  156. {
  157. Rect    growRect;
  158. register RgnHandle    tempRgn, clipRgn;
  159. register DocumentPeek doc;
  160.  
  161. if (window == gWPtr_IO) {
  162.     doc = (DocumentPeek) window;
  163. /* the growbox needs to be redrawn on activation: */
  164.     growRect = window->portRect;
  165. /* adjust for the scrollbars */
  166.     growRect.top = growRect.bottom - kScrollbarAdjust + 1;
  167.     growRect.left = growRect.right - kScrollbarAdjust + 1;
  168.     if (becomingActive) {
  169. /*    since we don’t want TEActivate to draw a selection in an area where
  170.     we’re going to erase and redraw, we’ll clip out the update region
  171.     before calling it. */
  172.         tempRgn = NewRgn();
  173.         clipRgn = NewRgn();
  174.         GetLocalUpdateRgn(window, tempRgn);        /* get localized update region */
  175.         GetClip(clipRgn);
  176.         DiffRgn(clipRgn, tempRgn, tempRgn);        /* subtract updateRgn from clipRgn */
  177.         SetClip(tempRgn);
  178.         TEActivate(doc->docTE);
  179.         gTheInput = doc->docTE;
  180.         SetClip(clipRgn);                        /* restore the full-blown clipRgn */
  181.         DisposeRgn(tempRgn);
  182.         DisposeRgn(clipRgn);
  183.         InvalRect(&growRect);    /* we cannot avoid grow box flickering */
  184. /* the controls must be redrawn on activation: */
  185.         if ((*doc->docVScroll)->contrlVis == 0) {
  186.             ShowControl(doc->docVScroll);
  187.             ValidRect(&(*doc->docVScroll)->contrlRect);
  188.             }
  189.         if ((*doc->docHScroll)->contrlVis == 0) {
  190.             ShowControl(doc->docHScroll);
  191.             ValidRect(&(*doc->docHScroll)->contrlRect);
  192.             }
  193.         }
  194.     else {        
  195.         TEDeactivate(doc->docTE);
  196.         gTheInput = nil;
  197. /* the controls must be redrawn on deactivation: */
  198.         HideControl(doc->docVScroll);
  199.         HideControl(doc->docHScroll);
  200.         InvalRect(&growRect);
  201.         }
  202.     }
  203. } /*DoActivate*/
  204.  
  205.  
  206. /*    This is called when a mouseDown occurs in the content of a window. */
  207.  
  208. void DoContentClick(WindowPtr window, EventRecord *event)
  209. {
  210. Rect    teRect;
  211. Point    mouse;
  212. ControlHandle control;
  213. TEHandle    theTE;
  214. DocumentPeek doc;
  215. long    tempc;
  216. TEPtr    tPtr;
  217. short    part, value, lines;
  218.  
  219. if (window == gWPtr_IO) {
  220.     mouse = event->where;                /* get the click position */
  221.     GlobalToLocal(&mouse);
  222.     doc = (DocumentPeek)window;
  223. /* see if we are in the viewRect. if so, we won’t check the controls */
  224.     GetTERect(window, &teRect);
  225.     theTE = doc->docTE;
  226.     if (PtInRect(mouse, &teRect)) {
  227.         /* see if we need to extend the selection */
  228.         TEClick(mouse, (event->modifiers & shiftKey) != 0, theTE);
  229.         AdjustScrollValues(window);
  230.         }
  231.     else {
  232.         part = FindControl(mouse, window, &control);
  233.         switch ( part ) {
  234.             case 0:        /* do nothing for viewRect case */
  235.                 break;
  236.             case inThumb:
  237.                 value = GetCtlValue(control);
  238.                 part = TrackControl(control, mouse, nil);
  239.                 if ( part ) {
  240.                     if ( control == doc->docVScroll ) {
  241.                         lines = LinesInTE(theTE);
  242.                         tPtr = *theTE;
  243.                         tempc = ((long)lines * tPtr->lineHeight) -
  244.                                 (tPtr->viewRect.bottom - tPtr->viewRect.top);
  245.                         TEPinScroll(0, tPtr->viewRect.top - tPtr->destRect.top -
  246.                             ((tempc * GetCtlValue(control)) / GetCtlMax(control)), theTE);
  247.                         }
  248.                     else
  249.                         TEPinScroll(value - GetCtlValue(control), 0, theTE);
  250.                     }
  251.                 break;
  252.             default:        /* clicked in an arrow, so track & scroll */
  253.                 {
  254.                 ControlActionUPP HVActionProcUPP = NewControlActionProc(control == doc->docVScroll ? (ProcPtr)VActionProc : (ProcPtr)HActionProc);
  255.  
  256.                 (void)TrackControl(control, mouse, HVActionProcUPP);
  257.                 if (HVActionProcUPP)
  258.                     DisposeRoutineDescriptor(HVActionProcUPP);
  259.                 }
  260.                 break;
  261.             }
  262.         }
  263.     }
  264. } /*DoContentClick*/
  265.  
  266.  
  267. /* This is called for any keyDown or autoKey events, except when the
  268.  Command key is held down. It looks at the frontmost window to decide what
  269.  to do with the key typed. */
  270.  
  271. void DoKeyDown(WindowPtr window, unsigned char key, Boolean isUserInput)
  272. {
  273. if (window == gWPtr_IO) {
  274.     TEKey(key, ((DocumentPeek) window)->docTE);
  275.     AdjustScrollbars(window, false);
  276.     if (isUserInput) {
  277.         gMMemory[kSIZE_RAM - 4] = 0;
  278.         gMMemory[kSIZE_RAM - 3] = key;
  279.         }
  280.     }
  281. } /*DoKeyDown*/
  282.  
  283. /* Determines how much to change the value of the vertical scrollbar by and how
  284.     much to scroll the TE record. */
  285.  
  286. pascal void VActionProc(ControlHandle control, short part)
  287. {
  288. register WindowPtr    window;
  289. register TEPtr        te;
  290. register short        amount;
  291.  
  292. if ( part ) {            /* if it was actually in the control */
  293.     window = (*control)->contrlOwner;
  294.     te = *((DocumentPeek) window)->docTE;
  295.     switch ( part ) {
  296.         case inUpButton:
  297.             amount = te->lineHeight;
  298.             break;
  299.         case inDownButton:
  300.             amount = - te->lineHeight;
  301.             break;
  302.         case inPageUp:
  303.             amount = te->viewRect.bottom - te->viewRect.top - te->lineHeight;
  304.             break;
  305.         case inPageDown:
  306.             amount = te->viewRect.top - te->viewRect.bottom + te->lineHeight;
  307.             break;
  308.         }
  309.     TEPinScroll(0, amount, ((DocumentPeek) window)->docTE);
  310.     AdjustVert(control, ((DocumentPeek) window)->docTE);
  311.     }
  312. } /* VActionProc */
  313.  
  314.  
  315. /* Determines how much to change the value of the horizontal scrollbar by and how
  316. much to scroll the TE record. */
  317.  
  318. pascal void HActionProc(ControlHandle control, short part)
  319. {
  320. register WindowPtr    window;
  321. register TEPtr        te;
  322. register short        amount;
  323.  
  324. if ( part ) {
  325.     window = (*control)->contrlOwner;
  326.     te = *((DocumentPeek) window)->docTE;
  327.     switch ( part ) {
  328.         case inUpButton:
  329.             amount = kButtonScroll;
  330.             break;
  331.         case inDownButton:
  332.             amount = - kButtonScroll;
  333.             break;
  334.         case inPageUp:
  335.             amount = te->viewRect.right - te->viewRect.left - kScrollbarAdjust;
  336.             break;
  337.         case inPageDown:
  338.             amount = te->viewRect.left - te->viewRect.right + kScrollbarAdjust;
  339.             break;
  340.         }
  341.     TEPinScroll(amount, 0, ((DocumentPeek) window)->docTE);
  342.     AdjustHorz(control, ((DocumentPeek) window)->docTE);
  343.     }
  344. } /* VActionProc */
  345.  
  346.  
  347. /* Draw the contents of an application window. */
  348.  
  349. void DrawWindow(WindowPtr window)
  350. {
  351. EraseRect(&window->portRect);
  352. TEUpdate(&(*((DocumentPeek)window)->docTE)->viewRect, ((DocumentPeek) window)->docTE);
  353. DrawGrowIcon(window);
  354. UpdtControl(window, window->visRgn);
  355. } /*DrawWindow*/
  356.  
  357.  
  358. /* Return a rectangle that is inset from the portRect by the size of
  359.     the scrollbars and a little extra margin. */
  360.  
  361. void GetTERect(WindowPtr window, RectPtr teRect)
  362. {
  363. *teRect = window->portRect;
  364. teRect->left += kTextMargin;
  365. teRect->bottom -= kScrollbarAdjust;        /* and for the scrollbars */
  366. teRect->right -= kScrollbarAdjust;
  367. } /*GetTERect*/
  368.  
  369. /* Scroll the TERec around to match up to the potentially updated scrollbar
  370.     values. This is really useful when the window has been resized such that the
  371.     scrollbars became inactive but the TERec was already scrolled. */
  372.  
  373. void AdjustTE(WindowPtr window)
  374. {
  375. register TEPtr        te;
  376.  
  377. te = *((DocumentPeek)window)->docTE;
  378. TEPinScroll((te->viewRect.left - te->destRect.left) -
  379.         GetCtlValue(((DocumentPeek)window)->docHScroll),
  380.         (te->viewRect.top - te->destRect.top) -
  381.             (GetCtlValue(((DocumentPeek)window)->docVScroll) *
  382.             te->lineHeight),
  383.         ((DocumentPeek)window)->docTE);
  384. } /*AdjustTE*/
  385.  
  386.  
  387. /* Calculate the new control maximum value and current value, whether it is the
  388. horizontal or vertical scrollbar. The vertical max is calculated by comparing the
  389. number of lines to the vertical size of the viewRect. The horizontal max is
  390. calculated by comparing the maximum document width to the width of the viewRect.
  391. The current values are set by comparing the offset between the view and
  392. destination rects. */
  393.  
  394. void AdjustHorz(ControlHandle control, TEHandle docTE)
  395. {
  396. register TEPtr    te;
  397. register short    max, min;
  398.  
  399. te = *docTE;
  400. max = (qd.screenBits.bounds.right - qd.screenBits.bounds.left) -
  401.             (te->viewRect.right - te->viewRect.left);
  402. if ( max < (min = GetCtlMin(control)) )
  403.     max = min;
  404. SetCtlMax(control, max);
  405. te = *docTE;    /* SetCtlMax can move memory */
  406. SetCtlValue(control, te->viewRect.left - te->destRect.left);
  407. } /*AdjustHorz*/
  408.  
  409. void AdjustVert(ControlHandle control, TEHandle docTE)
  410. {
  411. register TEPtr    te;
  412. register short    max, lines, min, divisor;
  413.  
  414. lines = LinesInTE(docTE);
  415. te = *docTE;
  416. max = lines - ((te->viewRect.bottom - te->viewRect.top) / te->lineHeight);
  417. if ( max < (min = GetCtlMin(control)) ) max = min;
  418. SetCtlMax(control, max);
  419. te = *docTE;    /* SetCtlMax can move memory */
  420. divisor = ((long)lines * te->lineHeight) - (te->viewRect.bottom - te->viewRect.top) - (te->lineHeight >> 1);
  421. SetCtlValue(control, divisor ?
  422.     ((long)max * (te->viewRect.top - te->destRect.top)) / divisor
  423.     : 0);
  424. } /*AdjustVert*/
  425.  
  426. /* Simply call the adjust routines for the vertical and horizontal scrollbars */
  427.  
  428. void AdjustScrollValues(WindowPtr window)
  429. {
  430. register DocumentPeek doc;
  431.  
  432. doc = (DocumentPeek)window;
  433. AdjustHorz(doc->docHScroll, doc->docTE);
  434. AdjustVert(doc->docVScroll, doc->docTE);
  435. } /*AdjustScrollValues*/
  436.  
  437.  
  438. /* Re-calculate the position and size of the viewRect and the scrollbars */
  439.  
  440. void AdjustScrollSizes(WindowPtr window)
  441. {
  442. Rect        teRect;
  443. register DocumentPeek doc;
  444.  
  445. doc = (DocumentPeek) window;
  446. GetTERect(window, &teRect);            /* start with TERect */
  447. (*doc->docTE)->viewRect = teRect;
  448. SetupVertScrollBar(window, doc->docVScroll);
  449. SetupHorzScrollBar(window, doc->docHScroll);
  450. } /*AdjustScrollSizes*/
  451.  
  452. void AdjustScrollbars(WindowPtr window, Boolean needsResize)
  453. {
  454. if ( needsResize ) {        /* move & size as needed */
  455.     HideControl(((DocumentPeek) window)->docVScroll);
  456.     HideControl(((DocumentPeek) window)->docHScroll);
  457.     AdjustScrollSizes(window);
  458.     }
  459. AdjustScrollValues(window);    /* fool with max and current value */
  460. if ( needsResize ) {                        /* move & size as needed */
  461.     ShowControl(((DocumentPeek) window)->docVScroll);
  462.     ShowControl(((DocumentPeek) window)->docHScroll);
  463.     ValidRect(&(*((DocumentPeek) window)->docVScroll)->contrlRect);
  464.     ValidRect(&(*((DocumentPeek) window)->docHScroll)->contrlRect);
  465.     }
  466. } /* AdjustScrollbars */
  467.  
  468. /* LinesInTE: returns the number of lines in a TextEdit field;
  469. since it calls TEGetText, it _can_ move memory */
  470.  
  471. static short LinesInTE(TEHandle theTE)
  472. {
  473. register Handle    textHand;
  474. register short    lines;
  475.  
  476. lines = (*theTE)->nLines;
  477. textHand = (Handle)TEGetText(theTE);
  478. /* since nLines isn’t right if the last character is a return, check for that case */
  479. if ( *(*textHand + InlineGetHandleSize(textHand) - 1) == kCrChar )
  480.     lines++;
  481. return(lines);
  482. }
  483.  
  484. /* procedure called when closing the IO window */
  485.  
  486. void CloseIO(WindowPtr w)
  487. {
  488. DoCloseWindow(w, kMItem_IO);
  489. }
  490.  
  491. void RecalcIO(FabWindowPtr w, RgnBalloonCursPtr theObj)
  492. {
  493. Rect    tempRect;
  494.  
  495. GetTERect((WindowPtr)w, &tempRect);
  496. RectRgn(theObj->zoneLocal, &tempRect);
  497. }
  498.  
  499.